#include <iostream>
#include <stdint.h>
#include <string.h>

#if 1
/*
https://segmentfault.com/a/1190000011658363#articleHeader5
https://blog.csdn.net/qq_28205153/article/details/55798628


33030301000114374a86c520181217182642
68ec75c1e7bd27aa5084fe96f7250a13932f9e5db13e48e822b6565b487a569dd733ca0f2d77a4e90e1f1e86d84889a305894fee701d44d728d52dc1b8160efac82bfc63af167b3bde0392ecb2998061
2ffea0e8


330303010001143b86b2d020181218084615
68ec75c1e7bd27aa5084fe96f7250a1323407789145112981654323eab372f87595c3303c20240005637eacf464fe832fa285ef769d5340cc741d0fa00f930c2fc000de87e61d93a1dafc6ca7a4dc94d
ea7b951c

-------------------------
秘钥：
11223344556677aa
31313232333334343535363637376161

偏移向量
mplock1234567890
6d706c6f636b31323334353637383930
*/

const int sbox[16][16]= {
    {0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76},
    {0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0},
    {0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15},
    {0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75},
    {0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84},
    {0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf},
    {0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8},
    {0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2},
    {0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73},
    {0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb},
    {0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79},
    {0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08},
    {0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a},
    {0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e},
    {0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf},
    {0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16},
};

const int reverse_sbox[16][16]={
        {0x52,0x9,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb},
        {0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb},
        {0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0xb,0x42,0xfa,0xc3,0x4e},
        {0x8,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25},
        {0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92},
        {0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84},
        {0x90,0xd8,0xab,0x0,0x8c,0xbc,0xd3,0xa,0xf7,0xe4,0x58,0x5,0xb8,0xb3,0x45,0x6},
        {0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0xf,0x2,0xc1,0xaf,0xbd,0x3,0x1,0x13,0x8a,0x6b},
        {0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73},
        {0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e},
        {0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0xe,0xaa,0x18,0xbe,0x1b},
        {0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4},
        {0x1f,0xdd,0xa8,0x33,0x88,0x7,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f},
        {0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0xd,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef},
        {0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61},
        {0x17,0x2b,0x4,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0xc,0x7d},
};

//encode 1 加密 ， 0 解密
void sub_byte(int array[4][4],int encode){
    int tmp,row,col;
    for(int i=0;i<4;i++){
        for(int j=0;j<4;j++){
            tmp=(uint8_t)array[i][j];
            row=tmp/16;     //行数
            col=tmp%16;     //列数

            if(1==encode){
                array[i][j]=sbox[row][col];
            }else if(0==encode){
                array[i][j]=reverse_sbox[row][col];
            }
        }
    }
}

/*
 * 第 K 行 左移 K-1 位
 *
 * -------------------------
 * |  1  |  2  |  3  |  4  |
 * -------------------------
 * |  1  |  2  |  3  |  4  |
 * -------------------------
 * |  1  |  2  |  3  |  4  |
 * -------------------------
 * |  1  |  2  |  3  |  4  |
 * -------------------------
 *           |||
 *            V
 * -------------------------
 * |  1  |  2  |  3  |  4  |            //第1行，左移1-1=0位
 * -------------------------
 * |  2  |  3  |  4  |  1  |            //第2行，左移2-1=1位
 * -------------------------
 * |  3  |  4  |  1  |  2  |            //第3行，左移3-1=2位
 * -------------------------
 * |  4  |  1  |  2  |  3  |            //第4行，左移4-1=3位
 * -------------------------
 * */

void shift_row(int array[4][4],int encode){
    //int shift=0;
    int tmp=0;
    for(int i=0;i<4;i++){
        for(int j=0;j<i;j++){
            //shift=(i+1)-1;
            if(1==encode){
                tmp=array[i][0];
                array[i][0]=array[i][1];
                array[i][1]=array[i][2];
                array[i][2]=array[i][3];
                array[i][3]=tmp;
            }else if(0==encode){
                tmp=array[i][3];
                array[i][3]=array[i][2];
                array[i][2]=array[i][1];
                array[i][1]=array[i][0];
                array[i][0]=tmp;
            }
        }
    }
}


//AES乘法计算
int aes_multiple_1(int a, int le){
    int thr = le & 0x8;
    int sec = le & 0x4;
    int fir = le & 0x2;
    int fir_mod = le % 2;
    int result = 0;
    if (thr){
        int b = a;
        for (int i = 1; i <=3 ; ++i) {
            b = b<<1;
            if (b >= 256)
                b = b ^ 0x11b;
        }
        b = b % 256;
        result = result ^ b;
    }
    if (sec){
        int b = a;
        for (int i = 1; i <=2 ; ++i) {
            b = b<<1;
            if (b >= 256)
                b = b ^ 0x11b;
        }
        b = b % 256;
        result = result ^ b;
    }
    if (fir){
        int b = a << 1;
        if (b >= 256)
            b = b ^ 0x11b;
        b = b % 256;
        result = result ^ b;
    }
    if (fir_mod)
        result = result ^ a;
    return  result;
}
void mixColumns_1(int a[4][4], int encode){
    //encode 为1代表列混淆，为0代表逆向列混 淆
    for (int i = 0; i < 4; ++i) {
        int temp0 = a[0][i];
        int temp1 = a[1][i];
        int temp2 = a[2][i];
        int temp3 = a[3][i];
        if (encode) {
            a[0][i] = aes_multiple_1(temp0, 2) ^ aes_multiple_1(temp1, 3) ^ temp2 ^ temp3;
            a[1][i] = temp0 ^ (aes_multiple_1(temp1, 2)) ^ (temp2 ^ aes_multiple_1(temp2, 2)) ^ temp3;
            a[2][i] = temp0 ^ temp1 ^ (aes_multiple_1(temp2, 2)) ^ (temp3 ^ aes_multiple_1(temp3, 2));
            a[3][i] = temp0 ^ (aes_multiple_1(temp0, 2)) ^ temp1 ^ temp2 ^ aes_multiple_1(temp3, 2);
        }else{
            a[0][i] = aes_multiple_1(temp0, 14) ^ aes_multiple_1(temp1, 11) ^ aes_multiple_1(temp2, 13) ^ aes_multiple_1(temp3, 9);
            a[1][i] = aes_multiple_1(temp0, 9) ^ aes_multiple_1(temp1, 14) ^ aes_multiple_1(temp2, 11) ^ aes_multiple_1(temp3, 13);
            a[2][i] = aes_multiple_1(temp0, 13) ^ aes_multiple_1(temp1, 9) ^ aes_multiple_1(temp2, 14) ^ aes_multiple_1(temp3, 11);
            a[3][i] = aes_multiple_1(temp0, 11) ^ aes_multiple_1(temp1, 13) ^ aes_multiple_1(temp2, 9) ^ aes_multiple_1(temp3, 14);
        }
    }
}

int mul_box[4][4]={
        {0x02,0x03,0x01,0x01},
        {0x01,0x02,0x03,0x01},
        {0x01,0x01,0x02,0x03},
        {0x03,0x01,0x01,0x02},
};
int reverse_mul_box[4][4]={
        {0x0e,0x0b,0x0d,0x09},
        {0x09,0x0e,0x0b,0x0d},
        {0x0d,0x09,0x0e,0x0b},
        {0x0b,0x0d,0x09,0x0e},
};

/*
uint8_t aes_multiple(uint8_t box_val,uint8_t val){      //TODO 逆向列混淆时不正确
    uint8_t result=0;
    if(box_val==0x01)
        return val;

    for(int i=0;i<4;i++) {      //因为box_val都是0x0*，高4位都是0
        if (0x01==(0x01&(box_val>>i))) {
            result ^= (uint8_t)(val << i);
        }
    }
    if(0x80==(0x80&val)){
        result^=0x1b;
    }
    //printf("val= %02x \n",result);
    return result;
}


void mix_column(uint8_t array[4][4],int encode){       //O³=64次
    static int i=0,j=0,n=0;

    uint8_t val[4];
    if(1==encode){
        for(i=0;i<4;i++){
            for(j=0;j<4;j++){
                val[j]=array[j][i];
                array[j][i]=0;
            }
            for(j=0;j<4;j++){
                for(n=0;n<4;n++){
                    //printf("%02x %02x %02x\n",mul_box[i][n], array[(j+n)%4][i],val[(j+n)%4]);     //array会被修改
                    //tmp[n] = aes_multiple(mul_box[i][n], array[(j+n)%4][i]);
                    array[(j+i)%4][i]^=aes_multiple(mul_box[i][n], val[(j+n)%4]);
                }
                //printf("%02x %02x %02x %02x\n",tmp[0],tmp[1],tmp[2],tmp[3]);
                //output[i][j]=(((tmp[0]^tmp[1])^tmp[2])^tmp[3]);
                //printf("output: %02x\n",output[j][i]);
            }
        }
    } else if (0==encode){
        printf("reverse\n");
        for(i=0;i<4;i++){
            for(j=0;j<4;j++){
                val[j]=array[j][i];
                array[j][i]=0;
            }
            for(j=0;j<4;j++){
                for(n=0;n<4;n++){
                    //printf("%02x %02x\n",reverse_mul_box[i][n],val[(j+n)%4]);
                    array[(j+i)%4][i]^=aes_multiple(reverse_mul_box[i][n], val[(j+n)%4]);
                }
                //printf("result: %02x\n",array[(j+i)%4][i]);
            }
        }
    }
}
*/

int sample[4][4]={
        {0x87,0xf2,0x4d,0x97},
        {0x6e,0x4c,0x90,0xec},
        {0x46,0xe7,0x4a,0xc3},
        {0xa6,0x8c,0xd8,0x95},
};

int temp[4][4]={
        {0x47,0x40,0xa3,0x4c},
        {0x37,0xd4,0x70,0x9f},
        {0x94,0xe4,0x3a,0x42},
        {0xed,0xa5,0xa6,0xbc},
};

int key[4][4]={      //秘钥
        {0x31,0x31,0x32,0x32},
        {0x33,0x33,0x34,0x34},
        {0x35,0x35,0x36,0x36},
        {0x37,0x37,0x61,0x61}
};

void xorkey(int original[4][4],int key[4][4]){
    for(int i=0;i<4;i++){
        for(int j=0;j<4;j++)
            original[i][j]=original[i][j]^key[j][i];		//TODO 需要验证 行 XOR 列 还是 行 XOR 行
    }
}
int RC[10] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};

void key_expansion(int key[4][4],int w[11][4][4]){
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            w[0][i][j] = key[j][i];
        }
    }
    for (int i = 1; i < 11; ++i){
        for (int j = 0; j < 4; ++j) {
            int tmp[4];
            if (j == 0){
                tmp[0] = w[i-1][3][1];
                tmp[1] = w[i-1][3][2];
                tmp[2] = w[i-1][3][3];
                tmp[3] = w[i-1][3][0];
                for (int k = 0; k < 4; ++k) {
                    int m = tmp[k];
                    int row = m / 16;
                    int column = m % 16;
                    tmp[k] = sbox[row][column];
                    if (k == 0){
                        tmp[k] = tmp[k] ^ RC[i-1];
                    }
                }
            } else{
                tmp[0] = w[i][j-1][0];
                tmp[1] = w[i][j-1][1];
                tmp[2] = w[i][j-1][2];
                tmp[3] = w[i][j-1][3];
            }
            for (int l = 0; l < 4; ++l) {

                w[i][j][l] = w[i-1][j][l] ^ tmp[l];
            }
        }
    }


}
/*
 * ECB：是一种基础的加密方式，密文被分割成分组长度相等的块（不足补齐），然后单独一个个加密，一个个输出组成密文。
 *
 * CBC：是一种循环模式，前一个分组的密文 和 当前分组的明文 异或 操作后再加密
 */
void encryption(int *content,int _key[4][4],int encode){
    int p[11][4][4];
    int tmp[4][4];
    key_expansion(_key,p);        //扩展秘钥
    for(int i=0;i<4;i++) {
        for (int j = 0; j < 4; j++) {
            tmp[i][j]=content[i*4+j];
        }
    }

    if(1==encode) {
        xorkey(tmp,p[0]);      //首先执行1次 轮秘钥加
        for (int i = 1; i <= 10; ++i) {      //10轮
            //xorkey(tmp,p[i-1]);
            sub_byte(tmp, encode);
            shift_row(tmp, encode);
            if (i != 10) {
                mixColumns_1(tmp, encode);      //第10次 不用列混淆
            }
            xorkey(tmp, p[i]);
        }
    }else if(0==encode){
        xorkey(tmp,p[10]);      //首先执行1次 轮秘钥加
        for (int i = 9; i >= 0; i--) {      //10轮
            //xorkey(tmp,p[i-1]);
            shift_row(tmp, encode);
            sub_byte(tmp, encode);
            xorkey(tmp, p[i]);
            if (i != 0) {
                mixColumns_1(tmp, encode);      //第0次 不用列混淆
            }
        }
    }
    for(int i=0;i<4;i++) {
        for (int j = 0; j < 4; j++) {
            content[i*4+j]=tmp[i][j];
        }
    }

}
//int file[]={
//        0x68 ,0xec ,0x75 ,0xc1 ,0xe7 ,0xbd ,0x27 ,0xaa ,0x50 ,0x84 ,0xfe ,0x96 ,0xf7 ,0x25 ,
//       0x0a ,0x13 ,0x23 ,0x40 ,0x77 ,0x89 ,0x14 ,0x51 ,0x12 ,0x98 ,0x16 ,0x54 ,0x32 ,0x3e ,
//       0xab ,0x37 ,0x2f ,0x87 ,0x59 ,0x5c ,0x33 ,0x03 ,0xc2 ,0x02 ,0x40 ,0x00 ,0x56 ,0x37 ,
//       0xea ,0xcf ,0x46 ,0x4f ,0xe8 ,0x32 ,0xfa ,0x28 ,0x5e ,0xf7 ,0x69 ,0xd5 ,0x34 ,0x0c ,
//       0xc7 ,0x41 ,0xd0 ,0xfa ,0x00 ,0xf9 ,0x30 ,0xc2 ,0xfc ,0x00 ,0x0d ,0xe8 ,0x7e ,0x61 ,
//       0xd9 ,0x3a ,0x1d ,0xaf ,0xc6 ,0xca ,0x7a ,0x4d ,0xc9 ,0x4d};
int file2[]= {
        0xAA, 0x01, 0x33, 0x00, 0x00, 0x00, 0x02, 0x38, 0x36, 0x38, 0x37, 0x34, 0x34, 0x30, 0x33, 0x39, 0x37, 0x31,
        0x37, 0x33, 0x36, 0x32, 0x00, 0x20, 0x18, 0x12, 0x12, 0x15, 0x56, 0x03, 0x20, 0x18, 0x12, 0x12, 0x17, 0x56,
        0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x27, 0x59, 0x43, 0x67, 0x45, 0x57, 0x69, 0x01,
        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x62, 0x65, 0x97,
        0x93, 0x60, 0x77, 0x06, 0x95, 0x88,0x84,0xb1
};
/*
 * encode=1 正向加密
 * encode=0 反向解密
 */

#define keyExpansion    key_expansion
#define addRoundKey     xorkey
#define subBytes        sub_byte
#define shiftRows       shift_row
#define mixColumns       mixColumns_1
void aes_detail(int *content,  int password[4][4], int encode){
    int p[11][4][4];
    int tmp[4][4];
    keyExpansion(password, p);

    for(int i=0;i<4;i++) {
        for (int j = 0; j < 4; j++) {
            tmp[i][j]=content[i*4+j];
        }
    }
    if (encode) {
        addRoundKey(tmp, p[0]);
        for (int i = 1; i <= 10; ++i) {
            subBytes(tmp, encode);
            shiftRows(tmp, encode);
            if (i != 10) {
                mixColumns(tmp, encode);
            }

            addRoundKey(tmp, p[i]);
        }
    }else {
        addRoundKey(tmp, p[10]);
        for (int i = 9; i >= 0; --i) {
            shiftRows(tmp, encode);
            subBytes(tmp, encode);
            addRoundKey(tmp, p[i]);
            if (i != 0) {
                mixColumns(tmp, encode);
            }
        }

        for(int i=0;i<4;i++) {
            for (int j = 0; j < 4; j++) {
                content[i*4+j]=tmp[i][j];
            }
        }
    }
}

//将字符转换为数值
int c2i(char ch) {
    // 如果是数字，则用数字的ASCII码减去48, 如果ch = '2' ,则 '2' - 48 = 2
    if(isdigit(ch))
        return ch - 48;

    // 如果是字母，但不是A~F,a~f则返回
    if( ch < 'A' || (ch > 'F' && ch < 'a') || ch > 'z' )
        return -1;

    // 如果是大写字母，则用数字的ASCII码减去55, 如果ch = 'A' ,则 'A' - 55 = 10
    // 如果是小写字母，则用数字的ASCII码减去87, 如果ch = 'a' ,则 'a' - 87 = 10
    if(isalpha(ch))
        return isupper(ch) ? ch - 55 : ch - 87;

    return -1;
}

char * password = "11223344556677aa";
int main() {
    int p[4][4];
    for (int m = 0; m < 4; ++m) {
        for (int i = 0; i < 4; ++i) {
            int indx = 4 * i + m;
            p[i][m] = 16 * c2i(password[indx]) + c2i(password[indx + 1]);
            //p[m][i]=password[m*4+i];

        }
    }
    int size=sizeof(file2)/sizeof(int);
    printf("size=%d\n",size);
    if(0==size/16)
        size/=16;
    else
        size=(size/16)+1;

    for(int i=0;i<size;i++) {
        encryption(&file2[i*16], p, 1);
    }

    printf("-------->\n");
    for (int i = 0; i <sizeof(file2)/sizeof(int); i++) {
            printf("%02x ",file2[i]);
    }



/*
    mixColumns_1(sample,1);
    printf("-------->\n");
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%02x ",sample[i][j]);
        }
        printf("\n");
    }

    mixColumns_1(temp,0);
    printf("-------->\n");
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%02x ",temp[i][j]);
        }
        printf("\n");
    }


    xorkey(temp,key);
    printf("-------->\n");
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%02x ",temp[i][j]);
        }
        printf("\n");
    }
    */



    return 0;
}

#else

#include <stdio.h>
#include <pbt.h>
#include <ctype.h>

void aes(char*, char*, char*, int);
void aes_detail(int[4][4], int[4][4], int);
void subBytes(int [4][4], int);
void shiftRows(int [4][4], int);
void mixColumns(int [4][4], int);
void addRoundKey(int [4][4], int[4][4]);
int aes_multiple(int, int);
void keyExpansion(int key[4][4], int w[11][4][4]);
int c2i(char );

/**
 * S盒
 */
static const int S_BOX[16][16] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
                                   0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
                                   0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
                                   0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
                                   0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
                                   0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
                                   0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
                                   0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
                                   0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
                                   0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
                                   0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
                                   0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
                                   0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
                                   0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
                                   0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
                                   0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };

/**
 * 逆S盒
 */
static const int INVERSE_S_BOX[16][16] = { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
                                           0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
                                           0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
                                           0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
                                           0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
                                           0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
                                           0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
                                           0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
                                           0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
                                           0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
                                           0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
                                           0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
                                           0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
                                           0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
                                           0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
                                           0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };
int RC[10] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
int main(){
    int method = 1;//1表示加密， 0表示解密
    //待加密/解密文件存放路径
    char * source_path = "F:\\aes2.txt";
    // 加密/解密后文件存放路径
    char *des_path = "F:\\aes3.txt";
    // 32位16进制密钥
    char * password = "11223344556677aa";
    aes(source_path, des_path, password, method);

    printf("\nsuccess!");

}
int file_2[]= {
        0xAA, 0x01, 0x33, 0x00, 0x00, 0x00, 0x02, 0x38, 0x36, 0x38, 0x37, 0x34, 0x34, 0x30, 0x33, 0x39, 0x37, 0x31,
        0x37, 0x33, 0x36, 0x32, 0x00, 0x20, 0x18, 0x12, 0x12, 0x15, 0x56, 0x03, 0x20, 0x18, 0x12, 0x12, 0x17, 0x56,
        0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x27, 0x59, 0x43, 0x67, 0x45, 0x57, 0x69, 0x01,
        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x62, 0x65, 0x97,
        0x93, 0x60, 0x77, 0x06, 0x95, 0x88
};

void aes(char* source_path, char* des_path, char* password, int method){
    //将密钥转换成4*4数组
    int p[4][4];
    for (int m = 0; m < 4; ++m) {
        for (int i = 0; i < 4; ++i) {
            int indx = 4 * i + m;
            p[i][m] = 16 * c2i(password[indx]) + c2i(password[indx + 1]);
        }
    }

    FILE *file = fopen(source_path, "r"); //获取文件的指针
    fseek(file, 0, SEEK_END); //移动文件的指针到文件结尾
    int len = sizeof(file_2); //获取文件的长度
    rewind(file); //将文件指针移动回文件开始
    // 如果文件长度不是128位（16字节）的整数倍，则补齐
    int size = len;
    if (len % 16 != 0) {
        size = (len / 16 + 1) * 16;
    }
    unsigned char content[size];
    //读取文件内容赋值给content
    fread(content, 1, len, file);
    for (int j = len; j < size; ++j) {
        content[j] = 0;
    }
    fclose(file);
    //存储结果


    unsigned char encry[size];
    //将文件转换成16字节的int型数组加密、解密
    for (int i = 0; i < size / 16; ++i) {

        int content_to_int[4][4];
        for (int j = 0; j < 4; ++j) {
            for (int k = 0; k < 4; ++k) {
                content_to_int[j][k] = file_2[j * 4 + k + 16 * i];
            }
        }
        aes_detail(content_to_int, p, method);
        for (int j = 0; j < 4; ++j) {
            for (int k = 0; k < 4; ++k) {
                encry[j * 4 + k + 16 * i] = content_to_int[j][k];
                printf("%02x",encry[j * 4 + k + 16 * i] );
            }
        }
    }


    FILE *file1 = fopen(des_path, "w");
    fwrite(encry, size, 1, file1);
    fflush(file1);
    fclose(file1);

}


void aes_detail(int content[4][4],  int password[4][4], int encode){
    int p[11][4][4];
    keyExpansion(password, p);

    if (encode) {
        addRoundKey(content, p[0]);
        for (int i = 1; i <= 10; ++i) {
            subBytes(content, encode);
            shiftRows(content, encode);
            if (i != 10) {
                mixColumns(content, encode);
            }

            addRoundKey(content, p[i]);
        }
    }else {
        addRoundKey(content, p[10]);
        for (int i = 9; i >= 0; --i) {
            shiftRows(content, encode);
            subBytes(content, encode);
            addRoundKey(content, p[i]);
            if (i != 0) {
                mixColumns(content, encode);
            }
        }
    }
}

void subBytes(int a[4][4], int encode){
    // encode 为1 代表字节替代，为0代表逆向字节替代
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            int temp = a[i][j];
            int row = temp / 16;
            int column = temp % 16;
            if (encode)
                a[i][j] = S_BOX[row][column];
            else
                a[i][j] = INVERSE_S_BOX[row][column];
        }
    }
}

void shiftRows(int a[4][4], int encode){
    //encode 为1代表行移位，为0代表逆向行移位
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < i; ++j) {
            if (encode) {
                int temp = a[i][0];
                a[i][0] = a[i][1];
                a[i][1] = a[i][2];
                a[i][2] = a[i][3];
                a[i][3] = temp;
            } else{
                int temp = a[i][3];
                a[i][3] = a[i][2];
                a[i][2] = a[i][1];
                a[i][1] = a[i][0];
                a[i][0] = temp;
            }
        }
    }
}

void mixColumns(int a[4][4], int encode){
    //encode 为1代表列混淆，为0代表逆向列混淆
    for (int i = 0; i < 4; ++i) {
        int temp0 = a[0][i];
        int temp1 = a[1][i];
        int temp2 = a[2][i];
        int temp3 = a[3][i];
        if (encode) {
            a[0][i] = aes_multiple(temp0, 2) ^ aes_multiple(temp1, 3) ^ temp2 ^ temp3;
            a[1][i] = temp0 ^ (aes_multiple(temp1, 2)) ^ (temp2 ^ aes_multiple(temp2, 2)) ^ temp3;
            a[2][i] = temp0 ^ temp1 ^ (aes_multiple(temp2, 2)) ^ (temp3 ^ aes_multiple(temp3, 2));
            a[3][i] = temp0 ^ (aes_multiple(temp0, 2)) ^ temp1 ^ temp2 ^ aes_multiple(temp3, 2);
        }else{
            a[0][i] = aes_multiple(temp0, 14) ^ aes_multiple(temp1, 11) ^ aes_multiple(temp2, 13) ^ aes_multiple(temp3, 9);
            a[1][i] = aes_multiple(temp0, 9) ^ aes_multiple(temp1, 14) ^ aes_multiple(temp2, 11) ^ aes_multiple(temp3, 13);
            a[2][i] = aes_multiple(temp0, 13) ^ aes_multiple(temp1, 9) ^ aes_multiple(temp2, 14) ^ aes_multiple(temp3, 11);
            a[3][i] = aes_multiple(temp0, 11) ^ aes_multiple(temp1, 13) ^ aes_multiple(temp2, 9) ^ aes_multiple(temp3, 14);
        }
    }
}

void addRoundKey(int a[4][4], int k[4][4]){
    // 由于用w[11][4][4]表示W[44]导致行列转置，所以在进行异或操作的时候应该是a[i，j] 异或 k[j,i]
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            a[i][j] = a[i][j] ^ k[j][i];
        }
    }
}

//AES乘法计算
int aes_multiple(int a, int le){
    int thr = le & 0x8;
    int sec = le & 0x4;
    int fir = le & 0x2;
    int fir_mod = le % 2;
    int result = 0;
    if (thr){
        int b = a;
        for (int i = 1; i <=3 ; ++i) {
            b = b<<1;
            if (b >= 256)
                b = b ^ 0x11b;
        }
        b = b % 256;
        result = result ^ b;
    }
    if (sec){
        int b = a;
        for (int i = 1; i <=2 ; ++i) {
            b = b<<1;
            if (b >= 256)
                b = b ^ 0x11b;
        }
        b = b % 256;
        result = result ^ b;
    }
    if (fir){
        int b = a << 1;
        if (b >= 256)
            b = b ^ 0x11b;
        b = b % 256;
        result = result ^ b;
    }
    if (fir_mod)
        result = result ^ a;
    return  result;
}

void keyExpansion(int key[4][4], int w[11][4][4]){
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            w[0][i][j] = key[j][i];
        }
    }
    for (int i = 1; i < 11; ++i){
        for (int j = 0; j < 4; ++j) {
            int temp[4];
            if (j == 0){
                temp[0] = w[i-1][3][1];
                temp[1] = w[i-1][3][2];
                temp[2] = w[i-1][3][3];
                temp[3] = w[i-1][3][0];
                for (int k = 0; k < 4; ++k) {
                    int m = temp[k];
                    int row = m / 16;
                    int column = m % 16;
                    temp[k] = S_BOX[row][column];
                    if (k == 0){
                        temp[k] = temp[k] ^ RC[i-1];
                    }
                }
            } else{
                temp[0] = w[i][j-1][0];
                temp[1] = w[i][j-1][1];
                temp[2] = w[i][j-1][2];
                temp[3] = w[i][j-1][3];
            }
            for (int l = 0; l < 4; ++l) {
                w[i][j][l] = w[i-1][j][l] ^ temp[l];
            }

        }
    }

}

//将字符转换为数值
int c2i(char ch) {
    // 如果是数字，则用数字的ASCII码减去48, 如果ch = '2' ,则 '2' - 48 = 2
    if(isdigit(ch))
        return ch - 48;

    // 如果是字母，但不是A~F,a~f则返回
    if( ch < 'A' || (ch > 'F' && ch < 'a') || ch > 'z' )
        return -1;

    // 如果是大写字母，则用数字的ASCII码减去55, 如果ch = 'A' ,则 'A' - 55 = 10
    // 如果是小写字母，则用数字的ASCII码减去87, 如果ch = 'a' ,则 'a' - 87 = 10
    if(isalpha(ch))
        return isupper(ch) ? ch - 55 : ch - 87;

    return -1;
}


#endif

#if 0

#include <stdio.h>
/*aes_small.c*/
//辅助矩阵
/*s盒矩阵：The AES Substitution Table*/// 256 位的密匙256 位支持长度为32 个字符
static const unsigned char sbox[256]={	//static:内部变量  const：只读，不可变常量
        0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,
        0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
        0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,
        0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
        0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,
        0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
        0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,
        0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
        0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,
        0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
        0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,
        0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
        0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,
        0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
        0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,
        0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
        0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,
        0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
        0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,
        0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
        0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,
        0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
        0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,
        0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
        0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,
        0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
        0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,
        0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
        0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,
        0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
        0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,
        0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16,
};
//逆向S 盒矩阵
static const unsigned char contrary_sbox[256]={
        0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,
        0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,
        0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,
        0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,
        0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,
        0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,//0x4e
        0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,
        0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,
        0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,
        0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,
        0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,
        0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,
        0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,
        0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,
        0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,
        0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,
        0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,
        0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,
        0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,
        0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,
        0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,
        0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,
        0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,
        0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,
        0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,
        0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,
        0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,
        0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,
        0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,
        0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,
        0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,
        0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d,
};
/*轮常量表 The key schedule rcon table*/
static const unsigned char Rcon[10]={
        0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36};

//辅助函数
/*有限域*2乘法 The x2time() function */
static unsigned char x2time(unsigned char x)
{
    if (x&0x80)
    {
        return (((x<<1)^0x1B)&0xFF);
    }
    return x<<1;
}
/*有限域*3乘法 The x2time() function */
static unsigned char x3time(unsigned char x)
{
    return (x2time(x)^x);
}
/*有限域*4乘法 The x4time() function */
static unsigned char x4time(unsigned char x)
{
    return ( x2time(x2time(x)) );
}
/*有限域*8乘法 The x8time() function */
static unsigned char x8time(unsigned char x)
{
    return ( x2time(x2time(x2time(x))) );
}
/*有限域9乘法 The x9time() function */
static unsigned char x9time(unsigned char x)	//9:1001
{
    return ( x8time(x)^x );
}
/*有限域*B乘法 The xBtime() function */
static unsigned char xBtime(unsigned char x)	//B:1011
{
    return ( x8time(x)^x2time(x)^x );
}
/*有限域*D乘法 The xDtime() function */
static unsigned char xDtime(unsigned char x)	//D:1101
{
    return ( x8time(x)^x4time(x)^x );
}
/*有限域*E乘法 The xEtime() function */
static unsigned char xEtime(unsigned char x)	//E:1110
{
    return ( x8time(x)^x4time(x)^x2time(x) );
}

/****************************************************************************************************************/
/*第三类操作：列混合操作 MixColumns: Process the entire block*/
static void MixColumns(unsigned char *col)//列混合
{
    unsigned char tmp[4],xt[4];
    int i;
    for(i=0;i<4;i++,col+=4)  //col代表一列的基地址，col+4:下一列的基地址
    {
        /*
        xt[0]=x2time(col[0]);
        xt[1]=x2time(col[1]);
        xt[2]=x2time(col[2]);
        xt[3]=x2time(col[3]);
        //xt[n]代表*2   xt[n]^col[n]代表*3   col[n]代表*1
        tmp[0]=(xt[0])^(xt[1]^col[1])^col[2]^col[3];	//2 3 1 1
        tmp[1]=col[0]^(xt[1])^(xt[2]^col[2])^col[3];	//1 2 3 1
        tmp[2]=col[0]^col[1]^(xt[2])^(xt[3]^col[3]);	//1 1 2 3
        tmp[3]=(xt[0]^col[0])^col[1]^col[2]^(xt[3]);	//3 1 1 2
        */
        tmp[0]=x2time(col[0])^x3time(col[1])^col[2]^col[3];	//2 3 1 1
        tmp[1]=col[0]^x2time(col[1])^x3time(col[2])^col[3];	//1 2 3 1
        tmp[2]=col[0]^col[1]^x2time(col[2])^x3time(col[3]);	//1 1 2 3
        tmp[3]=x3time(col[0])^col[1]^col[2]^x2time(col[3]);	//3 1 1 2
        //修改后的值 直接在原矩阵上修改
        col[0]=tmp[0];
        col[1]=tmp[1];
        col[2]=tmp[2];
        col[3]=tmp[3];
    }
}
//逆向列混淆
static void Contrary_MixColumns(unsigned char *col)
{
    unsigned char tmp[4];
    unsigned char xt2[4];//colx2
    unsigned char xt4[4];//colx4
    unsigned char xt8[4];//colx8
    int x;
    for(x=0;x<4;x++,col+=4)
    {
        /*
        xt2[0]=x2time(col[0]);
        xt2[1]=x2time(col[1]);
        xt2[2]=x2time(col[2]);
        xt2[3]=x2time(col[3]);
        xt4[0]=x2time(xt2[0]);
        xt4[1]=x2time(xt2[1]);
        xt4[2]=x2time(xt2[2]);
        xt4[3]=x2time(xt2[3]);
        xt8[0]=x2time(xt4[0]);
        xt8[1]=x2time(xt4[1]);
        xt8[2]=x2time(xt4[2]);
        xt8[3]=x2time(xt4[3]);
        tmp[0]=xt8[0]^xt4[0]^xt2[0]^xt8[1]^xt2[1]^col[1]^xt8[2]^xt4[2]^col[2]^xt8[3]^col[3];
        tmp[1]=xt8[0]^col[0]^xt8[1]^xt4[1]^xt2[1]^xt8[2]^xt2[2]^col[2]^xt8[3]^xt4[3]^col[3];
        tmp[2]=xt8[0]^xt4[0]^col[0]^xt8[1]^col[1]^xt8[2]^xt4[2]^xt2[2]^xt8[3]^xt2[3]^col[3];
        tmp[3]=xt8[0]^xt2[0]^col[0]^xt8[1]^xt4[1]^col[1]^xt8[2]^col[2]^xt8[3]^xt4[3]^xt2[3];
        */
        tmp[0]=xEtime(col[0])^xBtime(col[1])^xDtime(col[2])^x9time(col[3]);
        tmp[1]=x9time(col[0])^xEtime(col[1])^xBtime(col[2])^xDtime(col[3]);
        tmp[2]=xDtime(col[0])^x9time(col[1])^xEtime(col[2])^xBtime(col[3]);
        tmp[3]=xBtime(col[0])^xDtime(col[1])^x9time(col[2])^xEtime(col[3]);
        col[0]=tmp[0];
        col[1]=tmp[1];
        col[2]=tmp[2];
        col[3]=tmp[3];
    }
}
/*第二类操作：行移位：行左循环移位 ShiftRows:Shifts the entire block*/
static void ShiftRows(unsigned char *col)//正向行移位
{
    /*
        1 5  9 13				5  9 13 1
        2 6 10 14				10 14 2 6
        3 7 11 15				15 3 7 11
        4 8 12 16				16 4 8 12
    */
    unsigned char t;
    /*1nd row*///左移1位
    t=col[1];col[1]=col[5];col[5]=col[9];col[9]=col[13];col[13]=t;
    /*2rd row*///左移2位，交换2次数字来实现
    t=col[2];col[2]=col[10];col[10]=t;
    t=col[6];col[6]=col[14];col[14]=t;
    /*3th row*///左移3位，相当于右移1次
    t=col[15];col[15]=col[11];col[11]=col[7];col[7]=col[3];col[3]=t;
    /*4th row*/	//第4行不移位
}
//逆向行移位
static void Contrary_ShiftRows(unsigned char *col)
{
    unsigned char t;
    /*1nd row*/
    t=col[13];col[13]=col[9];col[9]=col[5];col[5]=col[1];col[1]=t;
    /*2rd row*/
    t=col[2];col[2]=col[10];col[10]=t;
    t=col[6];col[6]=col[14];col[14]=t;
    /*3th row*/
    t=col[3];col[3]=col[7];col[7]=col[11];col[11]=col[15];col[15]=t;
    /*4th row*/	//第4行不移位
}
/*第一类操作：s盒字节代换替换 SubBytes*/
static void SubBytes(unsigned char *col)//字节代换
{
    int x;
    for(x=0;x<16;x++)
    {
        col[x]=sbox[col[x]];
    }
}
//逆向字节代换
static void Contrary_SubBytes(unsigned char *col)
{
    int x;
    for(x=0;x<16;x++)
    {
        col[x]=contrary_sbox[col[x]];
    }
}
/*第四类操作：轮密钥加 AddRoundKey*/
static void AddRoundKey(unsigned char *col,unsigned char *expansionkey,int round)//密匙加
{
    //扩展密钥：44*32bit =11*4* 4*8 =  16字节*11轮，每轮用16字节密钥
    //第0轮，只进行一次轮密钥加
    //第1-10轮，轮密钥加
    int x;
    for(x=0;x<16;x++)	//每1轮操作：4*32bit密钥 = 16个字节密钥
    {
        col[x]^=expansionkey[(round<<4)+x];
    }
}
/* AES加密总函数 10轮4类操作 Encrypt a single block with Nr Rounds(10,12,14)*/
void AesEncrypt(unsigned char *blk,unsigned char *expansionkey,int Nr)//加密一个区块
{
    //输入blk原文，直接在上面修改，输出blk密文
    //输入skey：
    //输入Nr = 10轮
    int round;
    //第1轮之前：轮密钥加
    AddRoundKey(blk,expansionkey,0);
    //第1-9轮：4类操作：字节代换、行移位、列混合、轮密钥加
    for(round=1;round<=(Nr-1);round++)
    {
        SubBytes(blk);		//输入16字节数组，直接在原数组上修改
        ShiftRows(blk);		//输入16字节数组，直接在原数组上修改
        MixColumns(blk);	//输入16字节数组，直接在原数组上修改
        AddRoundKey(blk,expansionkey,round);
    }
    //第10轮：不进行列混合
    SubBytes(blk);
    ShiftRows(blk);
    AddRoundKey(blk,expansionkey,Nr);
}
//AES 解密总函数
void Contrary_AesEncrypt(unsigned char *blk,unsigned char *expansionkey,int Nr)
{
    int x;
    /* unsigned char *contrary_key=key;
    for(x=0;x<11;x++,key+=16)
    Contrary_MixColumns(key);*/
    AddRoundKey(blk,expansionkey,Nr);
    Contrary_ShiftRows(blk);
    Contrary_SubBytes(blk);
    for(x=(Nr-1);x>=1;x--)
    {
        AddRoundKey(blk,expansionkey,x);
        Contrary_MixColumns(blk);
        Contrary_ShiftRows(blk);
        Contrary_SubBytes(blk);
    }
    AddRoundKey(blk,expansionkey,0);
}
/*//密钥编排，16字节--->44列32bit密钥生成--> 11组16字节:分别用于11轮 轮密钥加运算
Schedule a secret key for use.
*outkey[] must be 16*15 bytes in size
*Nk==number of 32 bit words in the key,e.g.,4,6,8
*Nr==number of rounds,e.g.,10,12,14
*/
void ScheduleKey(unsigned char *inkey,unsigned char *outkey,int Nk,int Nr)//安排一个保密密钥使用
{
    //inkey:初始16字节密钥key
    //outkey：11组*16字节扩展密钥expansionkey
    //Nk：4列
    //Nr：10轮round
    unsigned char temp[4],t;
    int x,i;
    /*copy the key*/
    //第0组：[0-3]直接拷贝
    for(i=0;i<(4*Nk);i++)
    {
        outkey[i]=inkey[i];
    }
    //第1-10组：[4-43]
    i=Nk;
    while(i<(4*(Nr+1))) //i=4~43 WORD 32bit的首字节地址，每一个4字节
    {//1次循环生成1个字节扩展密钥，4次循环生成一个WORD
        //temp：4字节数组：代表一个WORD密钥
        /*temp=w[i-1]*/
        //i不是4的倍数的时候
        //每个temp = 每个outkey32bit = 4字节
        for(x=0;x<4;x++)
            temp[x]=outkey[(4*(i-1))+x];	//i：32bit的首字节地址
        //i是4的倍数的时候
        if(i%Nk==0)
        {
            /*字循环：循环左移1字节 RotWord()*/
            t=temp[0];temp[0]=temp[1];temp[1]=temp[2];temp[2]=temp[3];temp[3]=t;
            /*字节代换：SubWord()*/
            for(x=0;x<4;x++)
            {
                temp[x]=sbox[temp[x]];
            }
            /*轮常量异或：Rcon[j]*/
            temp[0]^=Rcon[(i/Nk)-1];
        }
        //else if(Nk>6 && (i%Nk)==4)	//Nk>6的算法不同，暂时用不到
        //{
        //	/*SubWord*/
        //	for(x=0;x<4;x++)
        //	{
        //		temp[x]=sbox[temp[x]];
        //	}
        //}

        /*w[i] = w[i-4]^w[i-1]*/
        for(x=0;x<4;x++)
        {
            outkey[(4*i)+x]=outkey[(4*(i-Nk))+x]^temp[x];
        }
        ++i;
    }
}
int main(void) {
    /*
    pt：原文16字节-->密文
    key：原密钥16字节
    skey：密钥扩展44long
    sbox：s盒
    */

    unsigned char pt[17], key[17];
    unsigned char expansionkey[15 * 16];
    int i;
    int j;
    printf("please input plaintext\n");//输入无格式的字符串字符个数不得少于六个！！！！尽量用不同的数字或字母
    scanf("%s", pt);
    printf("please input key\n");//输入加密钥匙密匙个数不得低于六个！！！！尽量用不同的数字或字母
    scanf("%s", key);

    /*加密*/
    ScheduleKey(key, expansionkey, 4, 10);    //1、密钥扩展生成
    AesEncrypt(pt, expansionkey, 10);        //2、AES 加密
    printf("AesEncrypt text is: ");    //输出密码文件
    for (i = 0; i < 16; i++) {
        printf("%02x", pt[i]);
    }
    printf("\n");
    printf("\n");

    /*解密*/
    Contrary_AesEncrypt(pt, expansionkey, 10);//AES 解密
    printf("after Contrary_AesEncrypt,plaintext is: ");//将解密文件输出
    for (i = 0; i < 16; i++) {
        printf("%c ", pt[i]);
    }
    printf("\n");
    printf("\n");
    while (1);
    return 0;

}

#endif